package com.learm.socket.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Iterator;

public class NioSocketServer {

    public static void main(String[] args){
        try {
            NioSocketServer.server();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void server() throws IOException{
        //1. 获取通道
        ServerSocketChannel ssChannel = ServerSocketChannel.open();

        //2. 切换非阻塞模式
        ssChannel.configureBlocking(false);

        //3. 绑定连接
        ssChannel.bind(new InetSocketAddress(9898));

        //4. 获取选择器
        Selector selector = Selector.open();

        //5. 将通道注册到选择器上, 并且指定“监听接收事件”
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);

        //6. 轮询式的获取选择器上已经“准备就绪”的事件
        while(selector.select() > 0){

            System.out.println("循环来一波");
            //7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)   注意这里循环的是事件
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();



            while(it.hasNext()){
                //8. 获取准备“就绪”的是事件
                SelectionKey sk = it.next();

                //15. 取消选择键 SelectionKey
                it.remove();

                //9. 判断具体是什么事件准备就绪
                if(sk.isAcceptable()){
                    //10. 若“接收就绪”，获取客户端连接
                    SocketChannel sChannel = ssChannel.accept();

                    //11. 切换非阻塞模式
                    sChannel.configureBlocking(false);

                    //12. 将该通道注册到选择器上
                    sChannel.register(selector, SelectionKey.OP_READ);
                }else if(sk.isReadable()){

                    //13. 获取当前选择器上“读就绪”状态的通道
                    SocketChannel sChannel = (SocketChannel) sk.channel();

                    //14. 读取数据
                    ByteBuffer buf = ByteBuffer.allocate(1024);

                    int len = 0;
                    while((len = sChannel.read(buf)) > 0 ){
                        buf.flip();
                        String content = new String(buf.array(), 0, len);
                        System.out.println(content);
                        buf.clear();

                        sk = ssChannel.register(selector,SelectionKey.OP_WRITE);
                        //在key上携带一个附件，一会再写出去
                        sk.attach(content);
                    }
                }else if(sk.isWritable()){

                }


            }
        }
    }

    /**
     * 采用 nio 的方式，执行read操作还是阻塞的，但是
     * @throws IOException
     */
    public static void serverBlock() throws IOException {
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        FileChannel fileChannel=FileChannel.open(Paths.get("D://gc.log"), StandardOpenOption.WRITE,StandardOpenOption.CREATE);
        ssChannel.bind(new InetSocketAddress(9898));

        SocketChannel sChannel = ssChannel.accept();

        ByteBuffer buf = ByteBuffer.allocate(1024);

        StringBuilder content = new StringBuilder("服务端接受数据成功:");

        int readLength = 0;

        while(true){
            System.out.println("读一次客户端发送的内容");
            readLength = sChannel.read(buf);
            if(readLength == -1) break;
            buf.flip();
            fileChannel.write(buf);

            content.append(new String(buf.array(),0,readLength));
            buf.clear();
        }
        buf.put(content.toString().getBytes());//服务端给客户端发送数据
        buf.flip();
        sChannel.write(buf);
        sChannel.close();
        fileChannel.close();
        ssChannel.close();
    }
}
